package awk.aio2;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.nio.ByteBuffer;
import java.nio.channels.AsynchronousServerSocketChannel;
import java.nio.channels.AsynchronousSocketChannel;
import java.nio.channels.CompletionHandler;
import java.util.concurrent.CountDownLatch;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.Future;

/**
 * @author guo
 */
public class AsyncTimeServer implements Runnable {
    CountDownLatch latch;
    AsynchronousServerSocketChannel asynchronousServerSocketChannel;

    public AsyncTimeServer() {
        try {
            asynchronousServerSocketChannel = AsynchronousServerSocketChannel.open();
            asynchronousServerSocketChannel.bind(new InetSocketAddress(8010));
            System.out.println("the time server is start on port :" + 8010);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {
        //可以直接使用 AsynchronousChannelGroup 绑定线程池
        //但是该类实现了Runnable接口
        new Thread(new AsyncTimeServer(), "AIO-AsyncTimeServer-001").start();
    }

    @Override
    public void run() {
        //CountDownLatch 是一个并发工具类，他允许一个线程等待另一个线程完成后再执。这里是为了防止主线程启动完成后关闭
        latch = new CountDownLatch(1);
        //该方法是异步的接受来自该通道的客户端的连接请求，连接成功后调用CompletionHandler的completed或者failed方法
        //客户端连接成功或者失败后的回调处理类
        asynchronousServerSocketChannel.accept(this, new CompletionHandler<AsynchronousSocketChannel, AsyncTimeServer>() {
            @Override
            public void completed(AsynchronousSocketChannel socketChannel, AsyncTimeServer attachment) {
                try {
                    //服务端已经接收客户端成功了，为什么还要调用accept方法？因为一个channel可以接收成千上万个客户端
                    //当调用asynchronousServerSocketChannel.accept(this, new AcceptCompletionHandler())方法后，又有新的
                    //客户端连接接入，所以需要继续调用他的accept方法，接受其它客户端的接入，最终形成一个循环
                    attachment.asynchronousServerSocketChannel.accept(attachment, this);
                    ByteBuffer buffer = ByteBuffer.allocate(1024);
                    //异步读操作，参数的定义：第一个参数：接收缓冲区，用于异步从channel读取数据包；
                    //第二个参数：异步channel携带的附件，通知回调的时候作为入参参数，这里是作为ReadCompletionHandler的入参
                    //通知回调的业务handler，也就是数据从channel读到ByteBuffer完成后的回调handler，这里是ReadCompletionHandler
                    socketChannel.read(buffer, buffer, new ReadCompletionHandler(socketChannel));


                    Future<Integer> future = socketChannel.write(buffer);
                    future.get();
                    System.out.println("sent to client ths same ");
                } catch (InterruptedException | ExecutionException e) {
                    e.printStackTrace();
                }
            }

            @Override
            public void failed(Throwable exc, AsyncTimeServer attachment) {
                exc.printStackTrace();
                attachment.latch.countDown();
            }
        });
        try {
            //阻塞直到count down to 0
            latch.await();
        } catch (InterruptedException e) {
            e.printStackTrace();
        }
    }

}